/*
 * Copyright (C) 2005 Luca Veltri - University of Parma - Italy
 * 
 * This file is part of MjSip (http://www.mjsip.org)
 * 
 * MjSip is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * MjSip is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with MjSip; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * 
 * Author(s):
 * Luca Veltri (luca.veltri@unipr.it)
 */

package org.zoolu.tools;


import java.io.*;
import java.util.Date;
//import java.util.Locale;
//import java.text.DateFormat;
//import java.text.SimpleDateFormat;


/** Class Log allows the printing of log messages onto standard output
  * or files or any PrintStream.
  * <p>
  * Every Log has a <i>verboselevel</i> associated with it;
  * any log request with <i>loglevel</i> less or equal
  * to the <i>verbose-level</i> is logged.
  * <br>Verbose level 0 indicates no log. The log levels should be greater than 0.
  * <p>
  * Parameter <i>logname</i>, if non-null, is used as log header
  * (i.e. written at the begin of each log row).  
  */
public class Log
{

   /******************************* Attributes *******************************/

   /** (static) Default maximum log file size (4MB) */
   //public static final long MAX_SIZE=4096*1024; // 4MB
   public static final long MAX_SIZE=1024*1024; // 1MB

   /** The log output stream */
   PrintStream out_stream;

   /** The log tag at the beginning of each log row */
   String log_tag;

   /** The <i>log_level</i>.
     * <p>Only messages with a level less or equal this <i>log_level</i>
     * are effectively logged */
   int verbose_level;
   
   /** The maximum size of the log stream/file [bytes]
     * Value -1 indicates no maximum size */
   long max_size;
     
   /** The size of the log tag (e.g. "MyLog: " has tag_size=7) */
   int tag_size;

   /** Whether messages are logged */
   boolean do_log;

   /** The char counter of the already logged data */
   long counter;


   /****************************** Constructors ******************************/

   /** Associates a new Log to the PrintStream <i>outstream</i>.
     * Log size has no bound */
   public Log(PrintStream out_stream, String log_tag, int verbose_level)
   {  init(out_stream,log_tag,verbose_level,-1);
   }

   /** Associates a new Log to the file <i>filename</i>.
     * Log size is limited to the MAX_SIZE */
   public Log(String file_name, String log_tag, int verbose_level)
   {  PrintStream os=null;
      if (verbose_level>0)
      {  try { os=new PrintStream(new FileOutputStream(file_name)); } catch (IOException e) { e.printStackTrace(); }
         init(os,log_tag,verbose_level,MAX_SIZE);
      }
   }

   /** Associates a new Log to the file <i>filename</i>.
     * Log size is limited to <i>logsize</i> [bytes] */
   public Log(String file_name, String log_tag, int verbose_level, long max_size)
   {  PrintStream os=null;
      if (verbose_level>0)
      {  try { os=new PrintStream(new FileOutputStream(file_name)); } catch (IOException e) { e.printStackTrace(); }
         init(os,log_tag,verbose_level,max_size);
      }
      else
      {  init(null,log_tag,0,0);
         do_log=false;
      }
   }

   /** Associates a new Log to the file <i>filename</i>.
     * Log size is limited to <i>logsize</i> [bytes] */
   public Log(String file_name, String log_tag, int verbose_level, long max_size, boolean append)
   {  PrintStream os=null;
      if (verbose_level>0)
      {  try { os=new PrintStream(new FileOutputStream(file_name,append)); } catch (IOException e) { e.printStackTrace(); }
         init(os,log_tag,verbose_level,max_size);
      }
      else
      {  init(null,log_tag,0,0);
         do_log=false;
      }
   }


   /**************************** Protected methods ****************************/

   /** Initializes the log */
   protected void init(PrintStream out_stream, String log_tag, int verbose_level, long max_size) 
   {  this.out_stream=out_stream;
      this.log_tag=log_tag;
      this.verbose_level=verbose_level;
      this.max_size=max_size;
      
      if (log_tag!=null) tag_size=log_tag.length()+2; else tag_size=0;
      do_log=true;
      counter=0;
   }

   /** Flushes */
   protected Log flush()
   {  if (verbose_level>0) out_stream.flush();
      return this;
   }


   /***************************** Public methods *****************************/

   /** Closes the log */
   public void close() 
   {  do_log=false;
      out_stream.close();
   }

   /** Logs the Exception */
   public Log printException(Exception e, int level)
   {  //ByteArrayOutputStream err=new ByteArrayOutputStream();
      //e.printStackTrace(new PrintStream(err));
      //return println("Exception: "+err.toString(),level);
      return println("Exception: "+ExceptionPrinter.getStackTraceOf(e),level);
   }

   /** Logs the Exception.toString() and Exception.printStackTrace() */
   public Log printException(Exception e)
   {  return printException(e,1);
   }

   /** Logs the packet timestamp */
   public Log printPacketTimestamp(String proto, String remote_addr, int remote_port, int len, String message, int level)
   {  String str=remote_addr+":"+remote_port+"/"+proto+" ("+len+" bytes)";
      if (message!=null) str+=": "+message;
      println(DateFormat.formatHHMMSS(new Date())+", "+str,level);
      return this;
   }

   /** Prints the <i>log</i> if <i>level</i> isn't greater than the Log <i>verbose_level</i> */
   public Log println(String message, int level)
   {  return print(message+"\r\n",level).flush();
   }

   /** Prints the <i>log</i> if the Log <i>verbose_level</i> is greater than 0 */
   public Log println(String message)
   {  return println(message,1);
   }

   /** Prints the <i>log</i> if the Log <i>verbose_level</i> is greater than 0 */
   public Log print(String message)
   {  return print(message,1);
   }

   /** Prints the <i>log</i> if <i>level</i> isn't greater than the Log <i>verbose_level</i> */
   public Log print(String message, int level)
   {  if (do_log && level<=verbose_level)
      {  
         if (log_tag!=null) out_stream.print(log_tag+": "+message);
         else out_stream.print(message);
         
         if (max_size>=0)
         {  counter+=tag_size+message.length();
            if (counter>max_size)
            {  out_stream.println("\r\n----MAXIMUM LOG SIZE----\r\nSuccessive logs are lost.");
               do_log=false;
            }
         }
      }
      return this;
   }

}
